﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Informant.Authentication;
using Informant.Net;
using Informant.ErrorHandling;
using System.Net;
using Informant.Google.ErrorHandling;

namespace Informant.Google.Authentication
{
	public class GoogleAuthenticationClient : IGoogleAuthenticationClient
	{
		#region Fields

		private Dictionary<AuthenticationTokenKeys, Object> _tokens;
		private CookieWebClient _webClient = null;
		private IErrorHandler _errorHandler = null;

		#endregion

		public GoogleAuthenticationClient()
		{
			_webClient = new CookieWebClient();
			_errorHandler = new ErrorHandler();
		}

		#region IAuthenticationClient Members

		/// <summary>
		/// Gets a value indicating whether this instance is logged on.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is logged on; otherwise, <c>false</c>.
		/// </value>
		public Boolean LoggedOn
		{
			get
			{
				return _tokens[AuthenticationTokenKeys.AuthToken] != null && !String.IsNullOrEmpty(_tokens[AuthenticationTokenKeys.AuthToken].ToString())
					&& _tokens[AuthenticationTokenKeys.SessionToken] != null && !String.IsNullOrEmpty(_tokens[AuthenticationTokenKeys.SessionToken].ToString());
			}
		}
		/// <summary>
		/// Logs on the specified user.
		/// </summary>
		/// <param name="username">The username. (ex. "name@gmail.com" or just "name")</param>
		/// <param name="password">The password.</param>
		/// <returns></returns>
		/// <exception cref="System.Security.Authentication.AuthenticationException"/>
		/// <exception cref="System.Net.WebException"/>
		public Dictionary<AuthenticationTokenKeys, Object> LogOn(String username, String password)
		{
			_tokens = new Dictionary<AuthenticationTokenKeys, Object>();
			_tokens.Add(AuthenticationTokenKeys.SessionToken, RetrieveSessionToken(username, password));
			_tokens.Add(AuthenticationTokenKeys.AuthToken, RetrieveAuthToken(username, password));

			if (!(_tokens[AuthenticationTokenKeys.AuthToken] != null
				&& !String.IsNullOrEmpty(_tokens[AuthenticationTokenKeys.AuthToken].ToString())
				&& _tokens[AuthenticationTokenKeys.SessionToken] != null
				&& !String.IsNullOrEmpty(_tokens[AuthenticationTokenKeys.SessionToken].ToString())))
			{
				throw new System.Security.Authentication.AuthenticationException(
					ErrorResources.AuthenticationExceptionInvalidCredentialsOrTargetServerAddress);
			}
			return _tokens;
		}
		/// <summary>
		/// Logs off the current user.
		/// </summary>
		/// <returns></returns>
		/// <exception cref="System.Security.Authentication.AuthenticationException"/>
		/// <exception cref="System.Net.WebException"/>
		public Boolean LogOff()
		{
			Boolean loggedOut = ServerLogout();
			if (loggedOut)
			{
				_tokens = null;
				_webClient = null;
				_errorHandler = null;
			}
			return loggedOut;
		}

		#endregion

		#region IAuthenticationClient Helpers

		/// <summary>
		/// Retrieves the GALX.
		/// </summary>
		/// <returns></returns>
		/// <exception cref="System.Net.WebException"/>
		private String RetrieveGALX()
		{
			String result = null;
			try
			{
				result = _webClient.SimpleGet(URLResources.GALX_URL).FindMatchWithRegex(RegexResources.GALX, 1);
			}
			catch (WebException ex)
			{
				_errorHandler.MakeExceptionClientFriendly(ex);
			}
			return result;
		}
		/// <summary>
		/// Retrieves the auth token.
		/// </summary>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		/// <returns></returns>
		/// <exception cref="System.Security.Authentication.AuthenticationException"/>
		/// <exception cref="System.Net.WebException"/>
		private String RetrieveAuthToken(String username, String password)
		{
			String requestAuthenticationURL = String.Format(URLResources.AUTHENTICATE_URL, QualifyUsername(username), password);
			String result = null;
			try
			{
				result = _webClient.SimplePost(requestAuthenticationURL).FindMatchWithRegex(RegexResources.Auth, 1);
			}
			catch (WebException ex)
			{
				_errorHandler.MakeExceptionClientFriendly(ex);
			}
			return result;
		}
		/// <summary>
		/// Retrieves the session token.
		/// </summary>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		/// <returns></returns>
		/// <exception cref="System.Security.Authentication.AuthenticationException"/>
		/// <exception cref="System.Net.WebException"/>
		private String RetrieveSessionToken(String username, String password)
		{
			String requestSessionURL = String.Format(URLResources.LOGIN_URL, QualifyUsername(username), password, RetrieveGALX());
			String result = null;
			try
			{
				result = _webClient.SimplePost(requestSessionURL).FindMatchWithRegex(RegexResources.Session, 2);
			}
			catch (WebException ex)
			{
				_errorHandler.MakeExceptionClientFriendly(ex);
			}
			return result;
		}
		/// <summary>
		/// Logs out the current user.
		/// </summary>
		/// <returns></returns>
		/// <exception cref="System.Net.WebException"/>
		private Boolean ServerLogout()
		{
			Boolean succeeded = false;
			try
			{
				String result = _webClient.SimpleGet(URLResources.LOGOUT_URL);
				succeeded = true;
			}
			catch (WebException ex)
			{
				_errorHandler.MakeExceptionClientFriendly(ex);
			}
			return succeeded;
		}
		/// <summary>
		/// Qualifies the username.
		/// </summary>
		/// <param name="username">The username.</param>
		/// <returns></returns>
		private String QualifyUsername(String username)
		{
			String qualifiedUsername = username;
			String gmail = "@gmail.com";
			if (!qualifiedUsername.Contains(gmail))
			{
				qualifiedUsername = String.Concat(qualifiedUsername, gmail);
			}
			return qualifiedUsername;
		}

		#endregion

	}
}
